/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager.service;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelActionType;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.vmmanager.exception.VoManagerErrorCodes;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import com.inspur.edp.metadata.rtcustomization.spi.IMetadataRtReferenceManager;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MetadataRtReferenceService implements IMetadataRtReferenceManager {

    private HashMap<String, String> map = new HashMap<String, String>();
    private String errorCode = "MetadataReferenceService";
    //TODO 临时添加
    private String errorToken = "#GSPBefError# ";

    private void buildMetadataReference(GspMetadata metadata) {
        if (metadata.getRefs() == null) {
            metadata.setRefs(new ArrayList<MetadataReference>());
        }
        map.clear();

        CustomizationService service = SpringBeanUtils.getBean(CustomizationService.class);
        GspViewModel vm = (GspViewModel) metadata.getContent();
        // 虚拟vo无依赖
        if (vm.getIsVirtual()) {
            return;
        }

        // ① vm.Mapping
        String beId = vm.getMapping().getTargetMetadataId();
        addMappingBeReference(vm, beId, metadata, service);

        // ② obj
        dealObjectReference(vm, vm.getMainObject(), metadata, service);

        // ③ vm.Actions
        if (vm.getActions() != null && vm.getActions().getCount() > 0) {
            for (ViewModelAction action : vm.getActions()) {
                if (action.getType() == ViewModelActionType.VMAction) {
                    if (action instanceof MappedCdpAction) {
                        buildCompReference(vm, (MappedCdpAction) action, metadata, service);
                    } else {
                        throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0039, null,
                                vm.getCode(), vm.getName(), action.getCode(), action.getName(), action.getType().toString());
                    }
                }
            }
        }

        // ④ vm.DataExtendInfo
        //todo:
    }

    private void dealObjectReference(GspViewModel vm, GspViewObject obj, GspMetadata metadata, CustomizationService service) {
        if (obj.getIsVirtual()) {
            return;
        }

        // ① mapping
        addMappingBeReference(vm, obj.getMapping().getTargetMetadataId(), metadata, service);

        // ① Elemnet
        if (obj.getContainElements() != null && obj.getContainElements().getCount() > 0) {
            for (IGspCommonField ele : obj.getContainElements()) {
                dealElementReference(vm, (GspViewModelElement) ele, metadata, service);
            }
        }

        // ② Child
        if (obj.getContainChildObjects() != null && obj.getContainChildObjects().getCount() > 0) {
            for (IGspCommonObject childObj : obj.getContainChildObjects()) {
                dealObjectReference(vm, (GspViewObject) childObj, metadata, service);
            }
        }
    }

    private void dealElementReference(GspViewModel vm, GspViewModelElement ele, GspMetadata metadata, CustomizationService service) {
        //① mapping
        if (!ele.getIsVirtualViewElement()) {
            addMappingBeReference(vm, ele.getMapping().getTargetMetadataId(), metadata, service);
        }

        //② vmElement.Help
        //todo:
    }

    public void buildCompReference(GspViewModel vm, MappedCdpAction operation, GspMetadata metadata, CustomizationService service) {
        addMappingBeReference(vm, operation.getComponentEntityId(), metadata, service);
    }

    private void addMappingBeReference(GspViewModel vm, String refBeId, GspMetadata metadata, CustomizationService service) {
        if (refBeId == null || "".equals(refBeId) || map.containsKey(refBeId)) {
            return;
        }

        map.put(refBeId, refBeId);
        buildReference(vm, refBeId, metadata, service);
    }

    private void buildReference(GspViewModel vm, String refMetadataId, GspMetadata metadata, CustomizationService service) {
        if (refMetadataId == null || "".equals(refMetadataId)) {
            return;
        }
        for (MetadataReference metadataReference : metadata.getRefs()) {
            if (refMetadataId.equals(metadataReference.getDependentMetadata().getId())) {
                return;
            }
        }
//    CustomizationService refService =SpringBeanUtils.getBean(CustomizationService.class);
        GspMetadata refMetaData = MetadataUtil.getCustomMetadata(refMetadataId);
        if (refMetaData == null) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0040, null, vm.getCode(), vm.getName(), refMetadataId);
        }
        MetadataReference metadataReference = new MetadataReference();
        metadataReference.setMetadata(metadata.getHeader());
        metadataReference.setDependentMetadata(refMetaData.getHeader());
        metadata.getRefs().add(metadataReference);
    }

    public List<MetadataReference> getConstraint(GspMetadata metadata) {
        if (metadata.getRefs() != null) {
            metadata.getRefs().clear();
        }
        buildMetadataReference(metadata);
        List<MetadataReference> list = new ArrayList<>();
        if (metadata.getRefs() != null && metadata.getRefs().size() > 0) {
            for (MetadataReference item : metadata.getRefs()) {
                list.add(item);
            }
        }
        return list;
    }
}
